---
title: "handler.js reference"
description: "An example of what the handler.js file should look like."
---

**This page is intended for developers who want to create custom agent skills for AnythingLLM.**

## Rules & Guidelines

<ul className="nx-list-disc nx-list-inside nx-flex nx-flex-col nx-gap-2 nx-mt-2">
  <li>
    The `handler.js` file must export a `runtime` object with a `handler`
    function.
  </li>
  <li>
    The `handler` function must accept a single argument which is an object
    containing the parameters defined in the `plugin.json` `entrypoint`
    property, if any.
  </li>
  <li>
    The `handler` function must return a string value, anything else may break
    the agent invocation or loop indefinitely.
  </li>
  <li>
    You must use `require` to import any modules you need from the NodeJS
    standard library or any modules you have bundled with your custom agent
    skill.
  </li>
  <li>
    You must use `await` when making any calls to external APIs or services.
  </li>
  <li>
    You must wrap your entire custom agent skill in a `try`/`catch` block and
    return any error messages to the agent at invocation time.
  </li>
</ul>

## Available runtime properties and methods

### `this.runtimeArgs`

The `this.runtimeArgs` object contains the arguments that were passed to the `setup_args` from the `plugin.json` file.

You can access the value of a specific argument by using the `propertyName` as the key.

```js
// plugin.json excerpt
// "setup_args": {
//     "OPEN_METEO_API_KEY": {
//       "type": "string",
//       "required": false,
//       "input": {
//         "type": "text",
//         "default": "YOUR_OPEN_METEO_API_KEY",
//         "placeholder": "sk-1234567890",
//         "hint": "The API key for the open-meteo API"
//       },
//       "value": "sk-key-for-service",
//     }
//   },

this.runtimeArgs["OPEN_METEO_API_KEY"]; // 'sk-key-for-service'
```

### `this.introspect`

The `this.introspect` function is used to log "thoughts" or "observations" to the user interface while the agent is running.

```js
this.introspect("Hello, world!"); // must be a string - will be shown to user
```

### `this.logger`

The `this.logger` function is used to log messages to the console. This is useful for debugging your custom agent skill via logs.

```js
this.logger("Hello, world!"); // must be a string - will be printed to console while the agent is running
```

### `this.config`

The `this.config` object contains the configuration for your custom agent skill. Useful for when you need to know the name of your custom agent skill or the version or for logs.

```js
this.config.name; // 'Get Weather'
this.config.hubId; // 'open-meteo-weather-api'
this.config.version; // '1.0.0'
```

# Example `handler.js`

Objective: Get the weather for a given location latitude and longitude using the open-meteo API.

```js
// handler.js
// NOT RECOMMENDED: We're using an external module here for demonstration purposes
// this would be a module we bundled with our custom agent skill and would be located in the same folder as our handler.js file
// Do not require modules outside of the plugin folder. It is recommended to use require within a function scope instead of the global scope.
// const _ExternalApiCaller = require('./external-api-caller.js');

module.exports.runtime = {
  handler: async function ({ latitude, longitude }) {
    const callerId = `${this.config.name}-v${this.config.version}`;
    try {
      this.introspect(
        `${callerId} called with lat:${latitude} long:${longitude}...`
      );
      const response = await fetch(
        `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current_weather=true&hourly=temperature_2m,relativehumidity_2m,windspeed_10m`
      );
      const data = await response.json();
      const averageTemperature = this._getAverage(data, "temperature_2m");
      const averageHumidity = this._getAverage(data, "relativehumidity_2m");
      const averageWindSpeed = this._getAverage(data, "windspeed_10m");
      return JSON.stringify({
        averageTemperature,
        averageHumidity,
        averageWindSpeed,
      });
    } catch (e) {
      this.introspect(
        `${callerId} failed to invoke with lat:${latitude} long:${longitude}. Reason: ${e.message}`
      );
      this.logger(
        `${callerId} failed to invoke with lat:${latitude} long:${longitude}`,
        e.message
      );
      return `The tool failed to run for some reason. Here is all we know ${e.message}`;
    }
  },
  // Helper function to get the average of an array of numbers!
  _getAverage(data, property) {
    return (
      data.hourly[property].reduce((a, b) => a + b, 0) /
      data.hourly[property].length
    );
  },

  // Recommended: Use this method to call external APIs or services
  // by requiring the module in the function scope and only if the code execution reaches that line
  // this is to prevent any unforseen issues with the global scope and module loading/unloading.
  // This file should be placed in the same folder as your handler.js file.
  _doExternalApiCall(myProp) {
    const _ScopedExternalCaller = require("./external-api-caller.js");
    return _ScopedExternalCaller.doSomething(myProp);
  },
};
```
